home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-07-20 | 45.3 KB | 2,024 lines |
- #include <math.h>
- #include "../h/config.h"
- #include "../h/rt.h"
- #include "rproto.h"
- #include <ctype.h>
-
- #ifdef LargeInts
-
- extern int over_flow;
-
- /*
- * Conventions:
- *
- * Bignums entering this module and leaving it are too large to
- * be represented with T_Integer. So, externally, a given value
- * is always T_Integer or always T_Bignum.
- *
- * Routines outside this module operate on bignums by calling
- * a routine like
- *
- * bigadd(da, db, dx)
- *
- * where da, db, and dx are pointers to tended descriptors.
- * For the common case where one argument is a T_Integer, these
- * call routines like
- *
- * bigaddi(da, IntVal(*db), dx).
- *
- * The bigxxxi routines can convert an integer to bignum form;
- * they use itobig.
- *
- * The routines that actually do the work take (length, address)
- * pairs specifying unsigned base-B digit strings. The sign handling
- * is done in the bigxxx routines.
- */
-
- /*
- * Type for doing arithmetic on (2 * NB)-bit nonnegative numbers.
- * Normally unsigned but may be signed (with NB reduced appropriately)
- * if unsigned arithmetic is slow.
- */
-
- /* The bignum radix, B */
-
- #define B ((word)1 << NB)
-
- /* Bignum digits in a word */
-
- #define WORDLEN (WordBits / NB + (WordBits % NB != 0))
-
- /* size of a bignum block that will hold an integer */
-
- #define INTBIGBLK sizeof(struct b_bignum) + sizeof(DIGIT) * WORDLEN
-
- /* lo(uword d) : the low digit of a uword
- hi(uword d) : the rest, d is unsigned
- signed_hi(uword d) : the rest, d is signed
- dbl(DIGIT a, DIGIT b) : the two-digit uword [a,b] */
-
- #define lo(d) ((d) & (B - 1))
- #define hi(d) ((uword)(d) >> NB)
- #define dbl(a,b) (((uword)(a) << NB) + (b))
-
- #if ((-1) >> 1) < 0
- #define signed_hi(d) ((word)(d) >> NB)
- #else
- #define signbit ((uword)1 << (WordBits - NB - 1))
- #define signed_hi(d) ((word)((((uword)(d) >> NB) ^ signbit) - signbit))
- #endif
-
- /* BigNum(dptr dp) : the struct b_bignum pointed to by dp */
-
- #define BigNum(dp) ((struct b_bignum *)&BlkLoc(*dp)->bignumblk)
-
- /* LEN(struct b_bignum *b) : number of significant digits */
-
- #define LEN(b) ((b)->lsd - (b)->msd + 1)
-
- /* DIG(struct b_bignum *b, word i): pointer to ith most significant digit */
-
- #define DIG(b,i) (&(b)->digits[(b)->msd+(i)])
-
- /* ceil, ln: ceil may be 1 too high in case ln is inaccurate */
-
- #undef ceil
- #define ceil(x) ((word)((x) + 1.01))
- #define ln(n) (log((double)n))
-
- /* determine the number of words needed for a bignum block with n digits */
-
- #define BigNeed(n) ( ((sizeof(struct b_bignum) + ((n) - 1) * sizeof(DIGIT)) \
- + WordSize - 1) & -WordSize )
-
- /* copied from rconv.c */
-
- #if !EBCDIC
- #define tonum(c) (isdigit(c) ? (c)-'0' : 10+(((c)|(040))-'a'))
- #else /* !EBCDIC */
- int tonum(c)
- int c;
- {
- #ifdef SASC
- const static char *alphanum = "0123456789abcdefghijklmnopqrstuvwxyz" ;
- char *where;
-
- where = memchr(alphanum, tolower(c), 36);
- if (where == 0) return -1;
- return where - alphanum;
- #else /* SASC */
- if(isdigit(c)) return (c - '0');
- if( (c | ' ') >= 'A' & (c | ' ') <= 'I') return( c - 'A' );
- if( (c | ' ') >= 'J' & (c | ' ') <= 'R') return( (c - 'J') + 9 );
- if( (c | ' ') >= 'S' & (c | ' ') <= 'Z') return( (c - 'S') + 18 );
- return 0;
- #endif /* SASC */
- }
- #endif /* !EBCDIC */
-
- /* copied from oref.c */
-
- #define RandVal (RanScale*(k_random=(RandA*(long)k_random+RandC)&0x7fffffffL))
-
-
- hidden int mkdesc Params((struct b_bignum *x, dptr dx));
- hidden novalue itobig Params((word i, struct b_bignum *x, dptr dx));
-
- hidden novalue decout Params((FILE *f, DIGIT *n, word l));
-
- hidden int bigaddi Params((dptr da, word i, dptr dx));
- hidden int bigsubi Params((dptr da, word i, dptr dx));
- hidden int bigmuli Params((dptr da, word i, dptr dx));
- hidden int bigdivi Params((dptr da, word i, dptr dx));
- hidden int bigmodi Params((dptr da, word i, dptr dx));
- hidden int bigpowi Params((dptr da, word i, dptr dx));
- hidden int bigpowii Params((word a, word i, dptr dx));
- hidden word bigcmpi Params((dptr da, word i));
-
- hidden DIGIT add1 Params((DIGIT *u, DIGIT *v, DIGIT *w, word n));
- hidden word sub1 Params((DIGIT *u, DIGIT *v, DIGIT *w, word n));
- hidden novalue mul1 Params((DIGIT *u, DIGIT *v, DIGIT *w, word n, word m));
- hidden novalue div1
- Params((DIGIT *a, DIGIT *b, DIGIT *q, DIGIT *r, word m, word n));
- hidden novalue compl1 Params((DIGIT *u, DIGIT *w, word n));
- hidden word cmp1 Params((DIGIT *u, DIGIT *v, word n));
- hidden DIGIT addi1 Params((DIGIT *u, word k, DIGIT *w, word n));
- hidden novalue subi1 Params((DIGIT *u, word k, DIGIT *w, word n));
- hidden DIGIT muli1 Params((DIGIT *u, word k, int c, DIGIT *w, word n));
- hidden DIGIT divi1 Params((DIGIT *u, word k, DIGIT *w, word n));
- hidden DIGIT shifti1 Params((DIGIT *u, word k, DIGIT c, DIGIT *w, word n));
- hidden word cmpi1 Params((DIGIT *u, word k, word n));
-
- hidden novalue bdzero Params((DIGIT *dest, word l));
- hidden novalue bdcopy Params((DIGIT *src, DIGIT *dest, word l));
-
- /*
- * mkdesc -- put value into a descriptor
- */
-
- static int mkdesc(x, dx)
- struct b_bignum *x;
- dptr dx;
- {
- word xlen, cmp;
- static DIGIT maxword[WORDLEN] = { 1 << ((WordBits - 1) % NB) };
-
- /* suppress leading zero digits */
-
- while (x->msd != x->lsd && *DIG(x,0) == 0)
- x->msd++;
-
- /* put it into a word if it fits, otherwise return the bignum */
-
- xlen = LEN(x);
-
- if (xlen < WORDLEN ||
- (xlen == WORDLEN && ((cmp = cmp1(DIG(x,0), maxword, WORDLEN)) < 0 ||
- (cmp == (word)0 && x->sign)))) {
- word val = -(word)*DIG(x,0);
- word i;
-
- for (i = x->msd; ++i <= x->lsd; )
- val = (val << NB) - x->digits[i];
- if (!x->sign)
- val = -val;
- dx->dword = D_Integer;
- IntVal(*dx) = val;
- }
- else {
- dx->dword = D_Bignum;
- BlkLoc(*dx) = (union block *)x;
- }
- return Success;
- }
-
- /*
- * i -> big
- */
-
- static novalue itobig(i, x, dx)
- word i;
- struct b_bignum *x;
- dptr dx;
- {
- x->lsd = WORDLEN - 1;
- x->msd = WORDLEN;
- x->sign = 0;
-
- if (i == 0) {
- x->msd--;
- *DIG(x,0) = 0;
- }
- else if (i < 0) {
- word d = lo(i);
-
- if (d != 0) {
- d = B - d;
- i += B;
- }
- i = - signed_hi(i);
- x->msd--;
- *DIG(x,0) = d;
- x->sign = 1;
- }
-
- while (i != 0) {
- x->msd--;
- *DIG(x,0) = lo(i);
- i = hi(i);
- }
-
- dx->dword = D_Bignum;
- BlkLoc(*dx) = (union block *)x;
- }
-
- /*
- * string -> bignum
- */
-
- word bigradix(sign, r, s, dx)
- int sign; /* '-' or not */
- int r; /* radix 2 .. 36 */
- char *s; /* input string */
- dptr dx; /* output T_Integer or T_Bignum */
- {
- struct b_bignum *b;
- DIGIT *bd;
- word len;
- int c;
-
- if (r == 0)
- return CvtFail;
- len = ceil(strlen(s) * ln(r) / ln(B));
- if (blkreq(BigNeed(len)) == Error)
- return CvtFail;
- b = alcbignum(len);
- bd = DIG(b,0);
-
- bdzero(bd, len);
-
- if (r < 2 || r > 36)
- return CvtFail;
-
- for (c = *s++; isalnum(c); c = *s++) {
- c = tonum(c);
- if (c >= r)
- return CvtFail;
- muli1(bd, (word)r, c, bd, len);
- }
-
- while (isspace(c))
- c = *s++;
-
- if (c != '\0')
- return CvtFail;
-
- if (sign == '-')
- b->sign = 1;
-
- /* put value into dx and return the type */
-
- (void)mkdesc(b, dx);
- return Type(*dx);
- }
-
- /*
- * bignum -> real
- */
-
- double bigtoreal(da)
- dptr da;
- {
- word i;
- double r = 0;
- struct b_bignum *b = &BlkLoc(*da)->bignumblk;
-
- for (i = b->msd; i <= b->lsd; i++)
- r = r * B + b->digits[i];
-
- return (b->sign ? -r : r);
- }
- /*
- * real -> bignum
- */
-
- int realtobig(da, dx)
- dptr da, dx;
- {
- double x = BlkLoc(*da)->realblk.realval;
- struct b_bignum *b;
- word i, blen;
- word d;
-
- if (x > 0.9999 * MinLong && x < 0.9999 * MaxLong) {
- MakeInt((word)x, dx);
- return Success; /* got lucky; a simple integer suffices */
- }
-
- x = x > 0 ? x : -x;
- blen = ln(x) / ln(B) + 0.99;
- for (i = 0; i < blen; i++)
- x /= B;
- if (x >= 1.0) {
- x /= B;
- blen += 1;
- }
-
- if (blkreq(BigNeed(blen)) == Error)
- return Error;
- b = alcbignum(blen);
- for (i = 0; i < blen; i++) {
- d = (x *= B);
- *DIG(b,i) = d;
- x -= d;
- }
-
- b->sign = x < 0;
- return mkdesc(b, dx);
- }
-
- /*
- * bignum -> string
- */
-
- int bigtos(da, dx)
- dptr da, dx;
- {
- struct b_bignum *a, *temp;
- word alen = LEN(BigNum(da));
- word slen = ceil(alen * ln(B) / ln(10));
- char *p, *q;
-
- if (strreq(slen) == Error || blkreq(BigNeed(alen)) == Error)
- return CvtFail;
- a = BigNum(da);
- temp = alcbignum(alen);
- if (a->sign)
- slen++;
- q = alcstr("",slen);
- bdcopy(DIG(a,0), DIG(temp,0), alen);
- p = q += slen;
- while (cmpi1(DIG(temp,0), (word)0, alen))
- *--p = '0' + divi1(DIG(temp,0), (word)10, DIG(temp,0), alen);
- if (a->sign)
- *--p = '-';
- StrLen(*dx) = q - p;
- StrLoc(*dx) = p;
- return Cvt;
- }
-
- /*
- * bignum -> file
- */
-
- novalue bigprint(f, da)
- FILE *f;
- dptr da;
- {
- struct b_bignum *a, *temp;
- word alen = LEN(BigNum(da));
- word slen, dlen;
-
- slen = (BlkLoc(*da)->bignumblk.lsd - BlkLoc(*da)->bignumblk.msd + 1);
- dlen = slen * NB * 0.3010299956639812; /* 1 / log2(10) */
- if (dlen > MaxDigits) {
- fprintf(f, "integer(~%ld)",dlen - 2); /* center estimate */
- return;
- }
-
- if (blkreq(BigNeed(alen)) == Error) {
- fatalerr(0, NULL); /* not worth passing this one back */
- }
- temp = alcbignum(alen);
- a = BigNum(da);
- bdcopy(DIG(a,0), DIG(temp,0), alen);
- if (a->sign)
- putc('-', f);
- decout(f, DIG(temp,0), alen);
- }
-
- static novalue decout(f, n, l)
- FILE *f;
- DIGIT *n;
- word l;
- {
- word i = divi1(n, (word)10, n, l);
-
- if (cmpi1(n, (word)0, l))
- decout(f, n, l);
- putc('0' + i, f);
- }
-
- /*
- * da -> dx
- */
-
- int cpbignum(da, dx)
- dptr da, dx;
- {
- struct b_bignum *a;
- word alen = LEN(BigNum(da));
- struct b_bignum *x;
-
- if (blkreq(BigNeed(alen)) == Error)
- return Error;
- x = alcbignum(alen);
- a = BigNum(da);
- bdcopy(DIG(a,0), DIG(x,0), alen);
- x->sign = a->sign;
- return mkdesc(x, dx);
- }
-
- /*
- * da + db -> dx
- */
-
- int bigadd(da, db, dx)
- dptr da, db;
- dptr dx;
- {
- struct b_bignum *x, *a, *b;
- word alen, blen;
- word c;
-
- if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) {
- alen = LEN(BigNum(da));
- blen = LEN(BigNum(db));
- if (blkreq(BigNeed(alen > blen ? alen + 1 : blen + 1)) == Error)
- return Error;
- a = BigNum(da);
- b = BigNum(db);
- if (a->sign == b->sign) {
- if (alen > blen) {
- x = alcbignum(alen + 1);
- c = add1(DIG(a,alen-blen), DIG(b,0), DIG(x,alen-blen+1), blen);
- *DIG(x,0) = addi1(DIG(a,0), c, DIG(x,1), alen-blen);
- }
- else if (alen == blen) {
- x = alcbignum(alen + 1);
- *DIG(x,0) = add1(DIG(a,0), DIG(b,0), DIG(x,1), alen);
- }
- else {
- x = alcbignum(blen + 1);
- c = add1(DIG(b,blen-alen), DIG(a,0), DIG(x,blen-alen+1), alen);
- *DIG(x,0) = addi1(DIG(b,0), c, DIG(x,1), blen-alen);
- }
- x->sign = a->sign;
- }
- else {
- if (alen > blen) {
- x = alcbignum(alen);
- c = sub1(DIG(a,alen-blen), DIG(b,0), DIG(x,alen-blen), blen);
- subi1(DIG(a,0), -c, DIG(x,0), alen-blen);
- x->sign = a->sign;
- }
- else if (alen == blen) {
- x = alcbignum(alen);
- if (cmp1(DIG(a,0), DIG(b,0), alen) > 0) {
- (void)sub1(DIG(a,0), DIG(b,0), DIG(x,0), alen);
- x->sign = a->sign;
- }
- else {
- (void)sub1(DIG(b,0), DIG(a,0), DIG(x,0), alen);
- x->sign = b->sign;
- }
- }
- else {
- x = alcbignum(blen);
- c = sub1(DIG(b,blen-alen), DIG(a,0), DIG(x,blen-alen), alen);
- subi1(DIG(b,0), -c, DIG(x,0), blen-alen);
- x->sign = b->sign;
- }
- }
- return mkdesc(x, dx);
- }
- else if (Type(*da) == T_Bignum) /* bignum + integer */
- return bigaddi(da, IntVal(*db), dx);
- else if (Type(*db) == T_Bignum) /* integer + bignum */
- return bigaddi(db, IntVal(*da), dx);
- else { /* integer + integer */
- struct descrip td;
- char tdigits[INTBIGBLK];
-
- itobig(IntVal(*da), (struct b_bignum *)tdigits, &td);
- return bigaddi(&td, IntVal(*db), dx);
- }
- }
-
- /*
- * da - db -> dx
- */
-
- int bigsub(da, db, dx)
- dptr da, db, dx;
- {
- struct descrip td;
- char tdigits[INTBIGBLK];
- struct b_bignum *a, *b, *x;
- word alen, blen;
- word c;
-
- if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) {
- alen = LEN(BigNum(da));
- blen = LEN(BigNum(db));
- if (blkreq(BigNeed(alen > blen ? alen + 1 : blen + 1)) == Error)
- return Error;
- a = BigNum(da);
- b = BigNum(db);
- if (a->sign != b->sign) {
- if (alen > blen) {
- x = alcbignum(alen + 1);
- c = add1(DIG(a,alen-blen), DIG(b,0), DIG(x,alen-blen+1), blen);
- *DIG(x,0) = addi1(DIG(a,0), c, DIG(x,1), alen-blen);
- }
- else if (alen == blen) {
- x = alcbignum(alen + 1);
- *DIG(x,0) = add1(DIG(a,0), DIG(b,0), DIG(x,1), alen);
- }
- else {
- x = alcbignum(blen + 1);
- c = add1(DIG(b,blen-alen), DIG(a,0), DIG(x,blen-alen+1), alen);
- *DIG(x,0) = addi1(DIG(b,0), c, DIG(x,1), blen-alen);
- }
- x->sign = a->sign;
- }
- else {
- if (alen > blen) {
- x = alcbignum(alen);
- c = sub1(DIG(a,alen-blen), DIG(b,0), DIG(x,alen-blen), blen);
- subi1(DIG(a,0), -c, DIG(x,0), alen-blen);
- x->sign = a->sign;
- }
- else if (alen == blen) {
- x = alcbignum(alen);
- if (cmp1(DIG(a,0), DIG(b,0), alen) > 0) {
- (void)sub1(DIG(a,0), DIG(b,0), DIG(x,0), alen);
- x->sign = a->sign;
- }
- else {
- (void)sub1(DIG(b,0), DIG(a,0), DIG(x,0), alen);
- x->sign = 1 ^ b->sign;
- }
- }
- else {
- x = alcbignum(blen);
- c = sub1(DIG(b,blen-alen), DIG(a,0), DIG(x,blen-alen), alen);
- subi1(DIG(b,0), -c, DIG(x,0), blen-alen);
- x->sign = 1 ^ b->sign;
- }
- }
- return mkdesc(x, dx);
- }
- else if (Type(*da) == T_Bignum) /* bignum - integer */
- return bigsubi(da, IntVal(*db), dx);
- else if (Type(*db) == T_Bignum) { /* integer - bignum */
- itobig(IntVal(*da), (struct b_bignum *)tdigits, &td);
- alen = LEN(BigNum(&td));
- blen = LEN(BigNum(db));
- if (blkreq(BigNeed(alen > blen ? alen + 1 : blen + 1)) == Error)
- return Error;
- a = BigNum(&td);
- b = BigNum(db);
- if (a->sign != b->sign) {
- if (alen == blen) {
- x = alcbignum(alen + 1);
- *DIG(x,0) = add1(DIG(a,0), DIG(b,0), DIG(x,1), alen);
- }
- else {
- x = alcbignum(blen + 1);
- c = add1(DIG(b,blen-alen), DIG(a,0), DIG(x,blen-alen+1), alen);
- *DIG(x,0) = addi1(DIG(b,0), c, DIG(x,1), blen-alen);
- }
- x->sign = a->sign;
- }
- else {
- if (alen == blen) {
- x = alcbignum(alen);
- if (cmp1(DIG(a,0), DIG(b,0), alen) > 0) {
- (void)sub1(DIG(a,0), DIG(b,0), DIG(x,0), alen);
- x->sign = a->sign;
- }
- else {
- (void)sub1(DIG(b,0), DIG(a,0), DIG(x,0), alen);
- x->sign = 1 ^ b->sign;
- }
- }
- else {
- x = alcbignum(blen);
- c = sub1(DIG(b,blen-alen), DIG(a,0), DIG(x,blen-alen), alen);
- subi1(DIG(b,0), -c, DIG(x,0), blen-alen);
- x->sign = 1 ^ b->sign;
- }
- }
- return mkdesc(x, dx);
- }
- else { /* integer - integer */
- itobig(IntVal(*da), (struct b_bignum *)tdigits, &td);
- return bigsubi(&td, IntVal(*db), dx);
- }
-
- }
-
- /*
- * da * db -> dx
- */
-
- int bigmul(da, db, dx)
- dptr da, db, dx;
- {
- struct b_bignum *a, *b, *x;
- word alen, blen;
-
- if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) {
- alen = LEN(BigNum(da));
- blen = LEN(BigNum(db));
- if (blkreq(BigNeed(alen + blen)) == Error)
- return Error;
- a = BigNum(da);
- b = BigNum(db);
- x = alcbignum(alen + blen);
- mul1(DIG(a,0), DIG(b,0), DIG(x,0), alen, blen);
- x->sign = a->sign ^ b->sign;
- return mkdesc(x, dx);
- }
- else if (Type(*da) == T_Bignum) /* bignum * integer */
- return bigmuli(da, IntVal(*db), dx);
- else if (Type(*db) == T_Bignum) /* integer * bignum */
- return bigmuli(db, IntVal(*da), dx);
- else { /* integer * integer */
- struct descrip td;
- char tdigits[INTBIGBLK];
-
- itobig(IntVal(*da), (struct b_bignum *)tdigits, &td);
- return bigmuli(&td, IntVal(*db), dx);
- }
- }
-
- /*
- * da / db -> dx
- */
-
- int bigdiv(da, db, dx)
- dptr da, db, dx;
- {
- struct b_bignum *a, *b, *x;
- word alen, blen;
-
- if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) {
- alen = LEN(BigNum(da));
- blen = LEN(BigNum(db));
- if (alen < blen) {
- MakeInt(0, dx);
- return Success;
- }
- if (blkreq(BigNeed(alen-blen+1)+BigNeed(alen+1)+BigNeed(blen)) == Error)
- return Error;
- a = BigNum(da);
- b = BigNum(db);
- x = alcbignum(alen - blen + 1);
- if (blen == 1)
- divi1(DIG(a,0), (word)*DIG(b,0), DIG(x,0), alen);
- else
- div1(DIG(a,0), DIG(b,0), DIG(x,0), NULL, alen-blen, blen);
- x->sign = a->sign ^ b->sign;
- return mkdesc(x, dx);
- }
- else if (Type(*da) == T_Bignum) /* bignum / integer */
- return bigdivi(da, IntVal(*db), dx);
- else if (Type(*db) == T_Bignum) { /* integer / bignum */
- MakeInt(0, dx);
- return Success;
- }
- /* not called for integer / integer */
- }
-
- /*
- * da % db -> dx
- */
-
- int bigmod(da, db, dx)
- dptr da, db, dx;
- {
- struct b_bignum *a, *b, *x, *temp;
- word alen, blen;
-
- if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) {
- alen = LEN(BigNum(da));
- blen = LEN(BigNum(db));
- if (alen < blen) {
- cpbignum(da, dx);
- return Success;
- }
- if (blkreq(BigNeed(blen)+BigNeed(alen+1)+BigNeed(blen)) == Error)
- return Error;
- a = BigNum(da);
- b = BigNum(db);
- x = alcbignum(blen);
- if (blen == 1) {
- temp = alcbignum(alen);
- *DIG(x,0) = divi1(DIG(a,0), (word)*DIG(b,0), DIG(temp,0), alen);
- }
- else
- div1(DIG(a,0), DIG(b,0), NULL, DIG(x,0), alen-blen, blen);
- x->sign = a->sign;
- return mkdesc(x, dx);
- }
- else if (Type(*da) == T_Bignum) /* bignum % integer */
- return bigmodi(da, IntVal(*db), dx);
- else if (Type(*db) == T_Bignum) { /* integer % bignum */
- struct descrip td;
- char tdigits[INTBIGBLK];
-
- itobig(IntVal(*da), (struct b_bignum *)tdigits, &td);
- cpbignum(&td, dx);
- return Success;
- }
- /* not called for integer % integer */
- }
-
- /*
- * -i -> dx
- */
-
- int bigneg(da, dx)
- dptr da, dx;
- {
- struct descrip td;
- char tdigits[INTBIGBLK];
-
- itobig(IntVal(*da), (struct b_bignum *)tdigits, &td);
- BigNum(&td)->sign ^= 1;
- return cpbignum(&td, dx);
- }
-
- /*
- * da ^ db -> dx
- */
-
- int bigpow(da, db, dx)
- dptr da, db, dx;
- {
- word n;
-
- if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) {
- if (BigNum(db)->sign) {
- MakeInt(0, dx);
- }
- else {
- n = LEN(BigNum(db)) * NB;
- /* scan bits left to right. skip leading 1. */
- while (--n >= 0)
- if ((*DIG(BigNum(db), n / NB) & (1 << (n % NB))))
- break;
- /* then, for each zero, square the partial result;
- * for each one, square it and multiply it by a */
- *dx = *da;
- while (--n >= 0) {
- if (bigmul(dx, dx, dx) == Error)
- return Error;
- if ((*DIG(BigNum(db), n / NB) & (1 << (n % NB))))
- if (bigmul(dx, da, dx) == Error)
- return Error;
- }
- }
- return Success;
- }
- else if (Type(*da) == T_Bignum) /* bignum ^ integer */
- return bigpowi(da, IntVal(*db), dx);
- else if (Type(*db) == T_Bignum) /* integer ^ bignum */
- return bigpowii(IntVal(*da), (word)bigtoreal(db), dx);
- else /* integer ^ integer */
- return bigpowii(IntVal(*da), IntVal(*db), dx);
- }
-
- /*
- * iand(da, db) -> dx
- */
-
- int bigand(da, db, dx)
- dptr da, db, dx;
- {
- struct b_bignum *a, *b, *x;
- word alen, blen, xlen;
- word i;
- struct b_bignum *tad, *tbd;
- DIGIT *ad, *bd;
- struct descrip td;
- char tdigits[INTBIGBLK];
-
- if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) {
- alen = LEN(BigNum(da));
- blen = LEN(BigNum(db));
- xlen = alen > blen ? alen : blen;
- if (blkreq(3 * BigNeed(xlen)) == Error)
- return Error;
- a = BigNum(da);
- b = BigNum(db);
- x = alcbignum(xlen);
-
- if (alen == xlen && !a->sign)
- ad = DIG(a,0);
- else {
- tad = alcbignum(xlen);
- ad = DIG(tad,0);
- bdzero(ad, xlen - alen);
- bdcopy(DIG(a,0), &ad[xlen-alen], alen);
- if (a->sign)
- compl1(ad, ad, xlen);
- }
-
- if (blen == xlen && !b->sign)
- bd = DIG(b,0);
- else {
- tbd = alcbignum(xlen);
- bd = DIG(tbd,0);
- bdzero(bd, xlen - blen);
- bdcopy(DIG(b,0), &bd[xlen-blen], blen);
- if (b->sign)
- compl1(bd, bd, xlen);
- }
-
- for (i = 0; i < xlen; i++)
- *DIG(x,i) = ad[i] & bd[i];
-
- if (a->sign & b->sign) {
- x->sign = 1;
- compl1(DIG(x,0), DIG(x,0), xlen);
- }
- }
- else if (Type(*da) == T_Bignum) { /* iand(bignum,integer) */
- itobig(IntVal(*db), (struct b_bignum *)tdigits, &td);
- alen = LEN(BigNum(da));
- blen = LEN(BigNum(&td));
- xlen = alen > blen ? alen : blen;
- if (blkreq(3 * BigNeed(alen)) == Error)
- return Error;
- a = BigNum(da);
- b = BigNum(&td);
- x = alcbignum(alen);
-
- if (alen == xlen && !a->sign)
- ad = DIG(a,0);
- else {
- tad = alcbignum(xlen);
- ad = DIG(tad,0);
- bdzero(ad, xlen - alen);
- bdcopy(DIG(a,0), &ad[xlen-alen], alen);
- if (a->sign)
- compl1(ad, ad, xlen);
- }
-
- if (blen == xlen && !b->sign)
- bd = DIG(b,0);
- else {
- tbd = alcbignum(xlen);
- bd = DIG(tbd,0);
- bdzero(bd, xlen - blen);
- bdcopy(DIG(b,0), &bd[xlen-blen], blen);
- if (b->sign)
- compl1(bd, bd, xlen);
- }
-
- for (i = 0; i < xlen; i++)
- *DIG(x,i) = ad[i] & bd[i];
-
- if (a->sign & b->sign) {
- x->sign = 1;
- compl1(DIG(x,0), DIG(x,0), xlen);
- }
- }
- else if (Type(*db) == T_Bignum) { /* iand(integer,bignum) */
- itobig(IntVal(*da), (struct b_bignum *)tdigits, &td);
- alen = LEN(BigNum(&td));
- blen = LEN(BigNum(db));
- xlen = alen > blen ? alen : blen;
- if (blkreq(3 * BigNeed(blen)) == Error)
- return Error;
- a = BigNum(&td);
- b = BigNum(db);
- x = alcbignum(blen);
-
- if (alen == xlen && !a->sign)
- ad = DIG(a,0);
- else {
- tad = alcbignum(xlen);
- ad = DIG(tad,0);
- bdzero(ad, xlen - alen);
- bdcopy(DIG(a,0), &ad[xlen-alen], alen);
- if (a->sign)
- compl1(ad, ad, xlen);
- }
-
- if (blen == xlen && !b->sign)
- bd = DIG(b,0);
- else {
- tbd = alcbignum(xlen);
- bd = DIG(tbd,0);
- bdzero(bd, xlen - blen);
- bdcopy(DIG(b,0), &bd[xlen-blen], blen);
- if (b->sign)
- compl1(bd, bd, xlen);
- }
-
- for (i = 0; i < xlen; i++)
- *DIG(x,i) = ad[i] & bd[i];
-
- if (a->sign & b->sign) {
- x->sign = 1;
- compl1(DIG(x,0), DIG(x,0), xlen);
- }
- }
- /* not called for iand(integer,integer) */
-
- return mkdesc(x, dx);
- }
-
- /*
- * ior(da, db) -> dx
- */
-
- int bigor(da, db, dx)
- dptr da, db, dx;
- {
- struct b_bignum *a, *b, *x;
- word alen, blen, xlen;
- word i;
- struct b_bignum *tad, *tbd;
- DIGIT *ad, *bd;
- struct descrip td;
- char tdigits[INTBIGBLK];
-
- if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) {
- alen = LEN(BigNum(da));
- blen = LEN(BigNum(db));
- xlen = alen > blen ? alen : blen;
- if (blkreq(3 * BigNeed(xlen)) == Error)
- return Error;
- a = BigNum(da);
- b = BigNum(db);
- x = alcbignum(xlen);
-
- if (alen == xlen && !a->sign)
- ad = DIG(a,0);
- else {
- tad = alcbignum(xlen);
- ad = DIG(tad,0);
- bdzero(ad, xlen - alen);
- bdcopy(DIG(a,0), &ad[xlen-alen], alen);
- if (a->sign)
- compl1(ad, ad, xlen);
- }
-
- if (blen == xlen && !b->sign)
- bd = DIG(b,0);
- else {
- tbd = alcbignum(xlen);
- bd = DIG(tbd,0);
- bdzero(bd, xlen - blen);
- bdcopy(DIG(b,0), &bd[xlen-blen], blen);
- if (b->sign)
- compl1(bd, bd, xlen);
- }
-
- for (i = 0; i < xlen; i++)
- *DIG(x,i) = ad[i] | bd[i];
-
- if (a->sign | b->sign) {
- x->sign = 1;
- compl1(DIG(x,0), DIG(x,0), xlen);
- }
- }
- else if (Type(*da) == T_Bignum) { /* ior(bignum,integer) */
- itobig(IntVal(*db), (struct b_bignum *)tdigits, &td);
- alen = LEN(BigNum(da));
- blen = LEN(BigNum(&td));
- xlen = alen > blen ? alen : blen;
- if (blkreq(3 * BigNeed(alen)) == Error)
- return Error;
- a = BigNum(da);
- b = BigNum(&td);
- x = alcbignum(alen);
-
- if (alen == xlen && !a->sign)
- ad = DIG(a,0);
- else {
- tad = alcbignum(xlen);
- ad = DIG(tad,0);
- bdzero(ad, xlen - alen);
- bdcopy(DIG(a,0), &ad[xlen-alen], alen);
- if (a->sign)
- compl1(ad, ad, xlen);
- }
-
- if (blen == xlen && !b->sign)
- bd = DIG(b,0);
- else {
- tbd = alcbignum(xlen);
- bd = DIG(tbd,0);
- bdzero(bd, xlen - blen);
- bdcopy(DIG(b,0), &bd[xlen-blen], blen);
- if (b->sign)
- compl1(bd, bd, xlen);
- }
-
- for (i = 0; i < xlen; i++)
- *DIG(x,i) = ad[i] | bd[i];
-
- if (a->sign | b->sign) {
- x->sign = 1;
- compl1(DIG(x,0), DIG(x,0), xlen);
- }
- }
- else if (Type(*db) == T_Bignum) { /* ior(integer,bignym) */
- itobig(IntVal(*da), (struct b_bignum *)tdigits, &td);
- alen = LEN(BigNum(&td));
- blen = LEN(BigNum(db));
- xlen = alen > blen ? alen : blen;
- if (blkreq(3 * BigNeed(blen)) == Error)
- return Error;
- a = BigNum(&td);
- b = BigNum(db);
- x = alcbignum(blen);
-
- if (alen == xlen && !a->sign)
- ad = DIG(a,0);
- else {
- tad = alcbignum(xlen);
- ad = DIG(tad,0);
- bdzero(ad, xlen - alen);
- bdcopy(DIG(a,0), &ad[xlen-alen], alen);
- if (a->sign)
- compl1(ad, ad, xlen);
- }
-
- if (blen == xlen && !b->sign)
- bd = DIG(b,0);
- else {
- tbd = alcbignum(xlen);
- bd = DIG(tbd,0);
- bdzero(bd, xlen - blen);
- bdcopy(DIG(b,0), &bd[xlen-blen], blen);
- if (b->sign)
- compl1(bd, bd, xlen);
- }
-
- for (i = 0; i < xlen; i++)
- *DIG(x,i) = ad[i] | bd[i];
-
- if (a->sign | b->sign) {
- x->sign = 1;
- compl1(DIG(x,0), DIG(x,0), xlen);
- }
- }
- /* not called for ior(integer,integer) */
-
- return mkdesc(x, dx);
- }
-
- /*
- * xor(da, db) -> dx
- */
-
- int bigxor(da, db, dx)
- dptr da, db, dx;
- {
- struct b_bignum *a, *b, *x;
- word alen, blen, xlen;
- word i;
- struct b_bignum *tad, *tbd;
- DIGIT *ad, *bd;
- struct descrip td;
- char tdigits[INTBIGBLK];
-
- if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) {
- alen = LEN(BigNum(da));
- blen = LEN(BigNum(db));
- xlen = alen > blen ? alen : blen;
- if (blkreq(3 * BigNeed(xlen)) == Error)
- return Error;
- a = BigNum(da);
- b = BigNum(db);
- x = alcbignum(xlen);
-
- if (alen == xlen && !a->sign)
- ad = DIG(a,0);
- else {
- tad = alcbignum(xlen);
- ad = DIG(tad,0);
- bdzero(ad, xlen - alen);
- bdcopy(DIG(a,0), &ad[xlen-alen], alen);
- if (a->sign)
- compl1(ad, ad, xlen);
- }
-
- if (blen == xlen && !b->sign)
- bd = DIG(b,0);
- else {
- tbd = alcbignum(xlen);
- bd = DIG(tbd,0);
- bdzero(bd, xlen - blen);
- bdcopy(DIG(b,0), &bd[xlen-blen], blen);
- if (b->sign)
- compl1(bd, bd, xlen);
- }
-
- for (i = 0; i < xlen; i++)
- *DIG(x,i) = ad[i] ^ bd[i];
-
- if (a->sign ^ b->sign) {
- x->sign = 1;
- compl1(DIG(x,0), DIG(x,0), xlen);
- }
- }
- else if (Type(*da) == T_Bignum) { /* ixor(bignum,integer) */
- itobig(IntVal(*db), (struct b_bignum *)tdigits, &td);
- alen = LEN(BigNum(da));
- blen = LEN(BigNum(&td));
- xlen = alen > blen ? alen : blen;
- if (blkreq(3 * BigNeed(alen)) == Error)
- return Error;
- a = BigNum(da);
- b = BigNum(&td);
- x = alcbignum(alen);
-
- if (alen == xlen && !a->sign)
- ad = DIG(a,0);
- else {
- tad = alcbignum(xlen);
- ad = DIG(tad,0);
- bdzero(ad, xlen - alen);
- bdcopy(DIG(a,0), &ad[xlen-alen], alen);
- if (a->sign)
- compl1(ad, ad, xlen);
- }
-
- if (blen == xlen && !b->sign)
- bd = DIG(b,0);
- else {
- tbd = alcbignum(xlen);
- bd = DIG(tbd,0);
- bdzero(bd, xlen - blen);
- bdcopy(DIG(b,0), &bd[xlen-blen], blen);
- if (b->sign)
- compl1(bd, bd, xlen);
- }
-
- for (i = 0; i < xlen; i++)
- *DIG(x,i) = ad[i] ^ bd[i];
-
- if (a->sign ^ b->sign) {
- x->sign = 1;
- compl1(DIG(x,0), DIG(x,0), xlen);
- }
- }
- else if (Type(*db) == T_Bignum) { /* ixor(integer,bignum) */
- itobig(IntVal(*da), (struct b_bignum *)tdigits, &td);
- alen = LEN(BigNum(&td));
- blen = LEN(BigNum(db));
- xlen = alen > blen ? alen : blen;
- if (blkreq(3 * BigNeed(blen)) == Error)
- return Error;
- a = BigNum(&td);
- b = BigNum(db);
- x = alcbignum(blen);
-
- if (alen == xlen && !a->sign)
- ad = DIG(a,0);
- else {
- tad = alcbignum(xlen);
- ad = DIG(tad,0);
- bdzero(ad, xlen - alen);
- bdcopy(DIG(a,0), &ad[xlen-alen], alen);
- if (a->sign)
- compl1(ad, ad, xlen);
- }
-
- if (blen == xlen && !b->sign)
- bd = DIG(b,0);
- else {
- tbd = alcbignum(xlen);
- bd = DIG(tbd,0);
- bdzero(bd, xlen - blen);
- bdcopy(DIG(b,0), &bd[xlen-blen], blen);
- if (b->sign)
- compl1(bd, bd, xlen);
- }
-
- for (i = 0; i < xlen; i++)
- *DIG(x,i) = ad[i] ^ bd[i];
-
- if (a->sign ^ b->sign) {
- x->sign = 1;
- compl1(DIG(x,0), DIG(x,0), xlen);
- }
- }
- /* not called for ixor(integer,integer) */
-
- return mkdesc(x, dx);
- }
-
- /*
- * bigshift(da, db) -> dx
- */
-
- int bigshift(da, db, dx)
- dptr da, db, dx;
- {
- struct b_bignum *a, *x;
- word alen;
- word r = IntVal(*db) % NB;
- word q = (r >= 0 ? IntVal(*db) : (IntVal(*db) - (r += NB))) / NB;
- word xlen;
- DIGIT *ad;
- struct b_bignum *tad;
- struct descrip td;
- char tdigits[INTBIGBLK];
-
- if (Type(*da) == T_Integer) {
- itobig(IntVal(*da), (struct b_bignum *)tdigits, &td);
- da = &td;
- }
-
- alen = LEN(BigNum(da));
- xlen = alen + q + 1;
- if (xlen <= 0) {
- MakeInt(0, dx);
- return Success;
- }
- else {
- if (blkreq(BigNeed(xlen) + BigNeed(alen)) == Error)
- return Error;
- a = BigNum(da);
- x = alcbignum(xlen);
-
- if (a->sign && IntVal(*db) > (word)0) {
- tad = alcbignum(alen);
- ad = DIG(tad,0);
- bdcopy(DIG(a,0), ad, alen);
- compl1(ad, ad, alen);
- }
- else
- ad = DIG(a,0);
-
- if (q >= 0) {
- *DIG(x,0) = shifti1(ad, r, (DIGIT)0, DIG(x,1), alen);
- bdzero(DIG(x,alen+1), q);
- }
- else
- *DIG(x,0) = shifti1(ad, r, ad[alen+q] >> (NB-r), DIG(x,1), alen+q);
-
- if (a->sign && IntVal(*db) > (word)0) {
- x->sign = 1;
- *DIG(x,0) |= B - (1 << r);
- compl1(DIG(x,0), DIG(x,0), xlen);
- }
- return mkdesc(x, dx);
- }
- }
-
- /*
- * negative if da < db
- * zero if da == db
- * positive if da > db
- */
-
- word bigcmp(da, db)
- dptr da, db;
- {
- struct b_bignum *a = BigNum(da);
- struct b_bignum *b = BigNum(db);
- word alen, blen;
-
- if (Type(*da) == T_Bignum && Type(*db) == T_Bignum) {
- if (a->sign != b->sign)
- return (b->sign - a->sign);
- alen = LEN(a);
- blen = LEN(b);
- if (alen != blen)
- return (a->sign ? blen - alen : alen - blen);
-
- if (a->sign)
- return cmp1(DIG(b,0), DIG(a,0), alen);
- else
- return cmp1(DIG(a,0), DIG(b,0), alen);
- }
- else if (Type(*da) == T_Bignum) /* cmp(bignum, integer) */
- return bigcmpi(da, IntVal(*db));
- else /* cmp(integer, bignum) */
- return -bigcmpi(db, IntVal(*da));
- }
-
- /*
- * ?da -> dx
- */
-
- int bigrand(da, dx)
- dptr da, dx;
- {
- struct b_bignum *a;
- word alen = LEN(BigNum(da));
- struct b_bignum *x;
- struct b_bignum *td;
- DIGIT *d;
- word i;
- double rval;
-
- if (blkreq(4 * BigNeed(alen + 1) + 4) == Error)
- return Error;
- x = alcbignum(alen);
- td = alcbignum(alen + 1);
- d = DIG(td,0);
- a = BigNum(da);
-
- for (i = alen; i >= 0; i--) {
- rval = RandVal;
- d[i] = rval * B;
- }
-
- div1(d, DIG(a,0), NULL, DIG(x,0), (word)1, alen);
- addi1(DIG(x,0), (word)1, DIG(x,0), alen);
- return mkdesc(x, dx);
- }
-
- /*
- * da + i -> dx
- */
-
- static int bigaddi(da, i, dx)
- dptr da, dx;
- word i;
- {
- struct b_bignum *a, *x;
- word alen;
-
- if (i < 0)
- return bigsubi(da, -i, dx);
- else if (i != (DIGIT)i) {
- struct descrip td;
- char tdigits[INTBIGBLK];
-
- itobig(i, (struct b_bignum *)tdigits, &td);
- return bigadd(da, &td, dx);
- }
- else {
- alen = LEN(BigNum(da));
- if (blkreq(BigNeed(alen + 1)) == Error)
- return Error;
- a = BigNum(da);
- if (a->sign) {
- x = alcbignum(alen);
- subi1(DIG(a,0), i, DIG(x,0), alen);
- }
- else {
- x = alcbignum(alen + 1);
- *DIG(x,0) = addi1(DIG(a,0), i, DIG(x,1), alen);
- }
- x->sign = a->sign;
- return mkdesc(x, dx);
- }
- }
-
- /*
- * da - i -> dx
- */
-
- static int bigsubi(da, i, dx)
- dptr da, dx;
- word i;
- {
- struct b_bignum *a, *x;
- word alen;
-
- if (i < 0)
- return bigaddi(da, -i, dx);
- else if (i != (DIGIT)i) {
- struct descrip td;
- char tdigits[INTBIGBLK];
-
- itobig(i, (struct b_bignum *)tdigits, &td);
- return bigsub(da, &td, dx);
- }
- else {
- alen = LEN(BigNum(da));
- if (blkreq(BigNeed(alen + 1)) == Error)
- return Error;
- a = BigNum(da);
- if (a->sign) {
- x = alcbignum(alen + 1);
- *DIG(x,0) = addi1(DIG(a,0), i, DIG(x,1), alen);
- }
- else {
- x = alcbignum(alen);
- subi1(DIG(a,0), i, DIG(x,0), alen);
- }
- x->sign = a->sign;
- return mkdesc(x, dx);
- }
- }
-
- /*
- * da * i -> dx
- */
-
- static int bigmuli(da, i, dx)
- dptr da, dx;
- word i;
- {
- struct b_bignum *a, *x;
- word alen;
-
- if (i <= -B || i >= B) {
- struct descrip td;
- char tdigits[INTBIGBLK];
-
- itobig(i, (struct b_bignum *)tdigits, &td);
- return bigmul(da, &td, dx);
- }
- else {
- alen = LEN(BigNum(da));
- if (blkreq(BigNeed(alen + 1)) == Error)
- return Error;
- a = BigNum(da);
- x = alcbignum(alen + 1);
- if (i >= 0)
- x->sign = a->sign;
- else {
- x->sign = 1 ^ a->sign;
- i = -i;
- }
- *DIG(x,0) = muli1(DIG(a,0), i, 0, DIG(x,1), alen);
- return mkdesc(x, dx);
- }
- }
-
- /*
- * da / i -> dx
- */
-
- static int bigdivi(da, i, dx)
- dptr da, dx;
- word i;
- {
- struct b_bignum *a, *x;
- word alen;
-
- if (i <= -B || i >= B) {
- struct descrip td;
- char tdigits[INTBIGBLK];
-
- itobig(i, (struct b_bignum *)tdigits, &td);
- return bigdiv(da, &td, dx);
- }
- else {
- alen = LEN(BigNum(da));
- if (blkreq(BigNeed(alen)) == Error)
- return Error;
- a = BigNum(da);
- x = alcbignum(alen);
- if (i >= 0)
- x->sign = a->sign;
- else {
- x->sign = 1 ^ a->sign;
- i = -i;
- }
- divi1(DIG(a,0), i, DIG(x,0), alen);
- return mkdesc(x, dx);
- }
- }
-
- /*
- * da % i -> dx
- */
-
- static int bigmodi(da, i, dx)
- dptr da, dx;
- word i;
- {
- struct b_bignum *a, *temp;
- word alen;
- word x;
-
- if (i <= -B || i >= B) {
- struct descrip td;
- char tdigits[INTBIGBLK];
-
- itobig(i, (struct b_bignum *)tdigits, &td);
- return bigmod(da, &td, dx);
- }
- else {
- alen = LEN(BigNum(da));
- if (blkreq(BigNeed(alen)) == Error)
- return Error;
- a = BigNum(da);
- temp = alcbignum(alen);
- x = divi1(DIG(a,0), Abs(i), DIG(temp,0), alen);
- if (a->sign)
- x = -x;
- MakeInt(x, dx);
- return Success;
- }
- }
-
- /*
- * da ^ i -> dx
- */
-
- static int bigpowi(da, i, dx)
- dptr da, dx;
- word i;
- {
- int n = WordBits;
-
- if (i > 0) {
- /* scan bits left to right. skip leading 1. */
- while (--n >= 0)
- if (i & ((word)1 << n))
- break;
- /* then, for each zero, square the partial result;
- for each one, square it and multiply it by a */
- *dx = *da;
- while (--n >= 0) {
- if (bigmul(dx, dx, dx) == Error)
- return Error;
- if (i & ((word)1 << n))
- if (bigmul(dx, da, dx) == Error)
- return Error;
- }
- }
- else {
- MakeInt(0, dx);
- }
- return Success;
- }
-
- /*
- * a ^ i -> dx
- */
-
- static int bigpowii(a, i, dx)
- word a, i;
- dptr dx;
- {
- word x, y;
- int n = WordBits;
- int isbig = 0;
-
- if (a == 0 || i <= 0) { /* special cases */
- if (a == 0 && i <= 0) /* 0 ^ negative -> error */
- RetError(-204, nulldesc);
- if (a == -1) { /* -1 ^ [odd,even] -> [-1,+1] */
- if (!(i & 1))
- a = 1;
- }
- else if (a != 1) { /* 1 ^ any -> 1 */
- a = 0;
- } /* others ^ negative -> 0 */
- MakeInt(a, dx);
- }
- else {
- struct descrip td;
- char tdigits[INTBIGBLK];
-
- /* scan bits left to right. skip leading 1. */
- while (--n >= 0)
- if (i & ((word)1 << n))
- break;
- /* then, for each zero, square the partial result;
- for each one, square it and multiply it by a */
- x = a;
- while (--n >= 0) {
- if (isbig) {
- if (bigmul(dx, dx, dx) == Error)
- return Error;
- }
- else {
- y = mul(x, x);
- if (!over_flow)
- x = y;
- else {
- itobig(x, (struct b_bignum *)tdigits, &td);
- if (bigmul(&td, &td, dx) == Error)
- return Error;
- isbig = (Type(*dx) == T_Bignum);
- }
- }
- if (i & ((word)1 << n)) {
- if (isbig) {
- if (bigmuli(dx, a, dx) == Error)
- return Error;
- }
- else {
- y = mul(x, a);
- if (!over_flow)
- x = y;
- else {
- itobig(x, (struct b_bignum *)tdigits, &td);
- if (bigmuli(&td, a, dx) == Error)
- return Error;
- isbig = (Type(*dx) == T_Bignum);
- }
- }
- }
- }
- if (!isbig) {
- MakeInt(x, dx);
- }
- }
- return Success;
- }
-
- /*
- * negative if da < i
- * zero if da == i
- * positive if da > i
- */
-
- static word bigcmpi(da, i)
- dptr da;
- word i;
- {
- struct b_bignum *a = BigNum(da);
- word alen = LEN(a);
-
- if (i > -B && i < B) {
- if (i >= 0)
- if (a->sign)
- return -1;
- else
- return cmpi1(DIG(a,0), i, alen);
- else
- if (a->sign)
- return -cmpi1(DIG(a,0), -i, alen);
- else
- return 1;
- }
- else {
- struct descrip td;
- char tdigits[INTBIGBLK];
-
- itobig(i, (struct b_bignum *)tdigits, &td);
- return bigcmp(da, &td);
- }
- }
-
-
- /* These are all straight out of Knuth vol. 2, Sec. 4.3.1. */
-
- /*
- * (u,n) + (v,n) -> (w,n)
- *
- * returns carry, 0 or 1
- */
-
- static DIGIT add1(u, v, w, n)
- DIGIT *u, *v, *w;
- word n;
- {
- uword dig, carry;
- word i;
-
- carry = 0;
- for (i = n; --i >= 0; ) {
- dig = (uword)u[i] + v[i] + carry;
- w[i] = lo(dig);
- carry = hi(dig);
- }
- return carry;
- }
-
- /*
- * (u,n) - (v,n) -> (w,n)
- *
- * returns carry, 0 or -1
- */
-
- static word sub1(u, v, w, n)
- DIGIT *u, *v, *w;
- word n;
- {
- uword dig, carry;
- word i;
-
- carry = 0;
- for (i = n; --i >= 0; ) {
- dig = (uword)u[i] - v[i] + carry;
- w[i] = lo(dig);
- carry = signed_hi(dig);
- }
- return carry;
- }
-
- /*
- * (u,n) * (v,m) -> (w,m+n)
- */
-
- static novalue mul1(u, v, w, n, m)
- DIGIT *u, *v, *w;
- word n, m;
- {
- word i, j;
- uword dig, carry;
-
- bdzero(&w[m], n);
-
- for (j = m; --j >= 0; ) {
- carry = 0;
- for (i = n; --i >= 0; ) {
- dig = (uword)u[i] * v[j] + w[i+j+1] + carry;
- w[i+j+1] = lo(dig);
- carry = hi(dig);
- }
- w[j] = carry;
- }
- }
-
- /*
- * (a,m+n) / (b,n) -> (q,m+1) (r,n)
- *
- * if q or r is NULL, the quotient or remainder is discarded
- */
-
- static novalue div1(a, b, q, r, m, n)
- DIGIT *a, *b, *q, *r;
- word m, n;
- {
- uword qhat, rhat;
- uword dig, carry;
- struct b_bignum *tu, *tv;
- DIGIT *u, *v;
- word d;
- word i, j;
-
- /* blkreq's done in calling routines */
-
- tu = alcbignum(m + n + 1);
- tv = alcbignum(n);
- u = DIG(tu,0);
- v = DIG(tv,0);
-
- /* D1 */
- for (d = 0; d < NB; d++)
- if (b[0] & (1 << (NB - 1 - d)))
- break;
-
- u[0] = shifti1(a, d, (DIGIT)0, &u[1], m+n);
- shifti1(b, d, (DIGIT)0, v, n);
-
- /* D2, D7 */
- for (j = 0; j <= m; j++) {
- /* D3 */
- if (u[j] == v[0]) {
- qhat = B - 1;
- rhat = (uword)v[0] + u[j+1];
- }
- else {
- uword numerator = dbl(u[j], u[j+1]);
- qhat = numerator / (uword)v[0];
- rhat = numerator % (uword)v[0];
- }
-
- while (rhat < B && qhat * v[1] > dbl(rhat, u[j+2])) {
- qhat -= 1;
- rhat += v[0];
- }
-
- /* D4 */
- carry = 0;
- for (i = n; i > 0; i--) {
- dig = u[i+j] - v[i-1] * qhat + carry; /* -BSQ+B .. B-1 */
- u[i+j] = lo(dig);
- if ((uword)dig < B)
- carry = hi(dig);
- else carry = hi(dig) | -B;
- }
- carry = (word)(carry + u[j]) < 0;
-
- /* D5 */
- if (q)
- q[j] = qhat;
-
- /* D6 */
- if (carry) {
- if (q)
- q[j] -= 1;
- carry = 0;
- for (i = n; i > 0; i--) {
- dig = (uword)u[i+j] + v[i-1] + carry;
- u[i+j] = lo(dig);
- carry = hi(dig);
- }
- }
- }
-
- if (r) {
- if (d == 0)
- shifti1(&u[m+1], (word)d, (DIGIT)0, r, n);
- else
- r[0] = shifti1(&u[m+1], (word)(NB - d), u[m+n]>>d, &r[1], n - 1);
- }
- }
-
- /*
- * - (u,n) -> (w,n)
- *
- */
-
- static novalue compl1(u, w, n)
- DIGIT *u, *w;
- word n;
- {
- uword dig, carry = 0;
- word i;
-
- for (i = n; --i >= 0; ) {
- dig = carry - u[i];
- w[i] = lo(dig);
- carry = signed_hi(dig);
- }
- }
-
- /*
- * (u,n) : (v,n)
- */
-
- static word cmp1(u, v, n)
- DIGIT *u, *v;
- word n;
- {
- word i;
-
- for (i = 0; i < n; i++)
- if (u[i] != v[i])
- return u[i] > v[i] ? 1 : -1;
- return 0;
- }
-
- /*
- * (u,n) + k -> (w,n)
- *
- * k in 0 .. B-1
- * returns carry, 0 or 1
- */
-
- static DIGIT addi1(u, k, w, n)
- DIGIT *u, *w;
- word k;
- word n;
- {
- uword dig, carry;
- word i;
-
- carry = k;
- for (i = n; --i >= 0; ) {
- dig = (uword)u[i] + carry;
- w[i] = lo(dig);
- carry = hi(dig);
- }
- return carry;
- }
-
- /*
- * (u,n) - k -> (w,n)
- *
- * k in 0 .. B-1
- * u must be greater than k
- */
-
- static novalue subi1(u, k, w, n)
- DIGIT *u, *w;
- word k;
- word n;
- {
- uword dig, carry;
- word i;
-
- carry = -k;
- for (i = n; --i >= 0; ) {
- dig = (uword)u[i] + carry;
- w[i] = lo(dig);
- carry = signed_hi(dig);
- }
- }
-
- /*
- * (u,n) * k + c -> (w,n)
- *
- * k in 0 .. B-1
- * returns carry, 0 .. B-1
- */
-
- static DIGIT muli1(u, k, c, w, n)
- DIGIT *u, *w;
- word k;
- int c;
- word n;
- {
- uword dig, carry;
- word i;
-
- carry = c;
- for (i = n; --i >= 0; ) {
- dig = (uword)k * u[i] + carry;
- w[i] = lo(dig);
- carry = hi(dig);
- }
- return carry;
- }
-
- /*
- * (u,n) / k -> (w,n)
- *
- * k in 0 .. B-1
- * returns remainder, 0 .. B-1
- */
-
- static DIGIT divi1(u, k, w, n)
- DIGIT *u, *w;
- word k;
- word n;
- {
- uword dig, remain;
- word i;
-
- remain = 0;
- for (i = 0; i < n; i++) {
- dig = dbl(remain, u[i]);
- w[i] = dig / k;
- remain = dig % k;
- }
- return remain;
- }
-
- /*
- * ((u,n) << k) + c -> (w,n)
- *
- * k in 0 .. NB-1
- * c in 0 .. B-1
- * returns carry, 0 .. B-1
- */
-
- static DIGIT shifti1(u, k, c, w, n)
- DIGIT *u, c, *w;
- word k;
- word n;
- {
- uword dig;
- word i;
-
- if (k == 0) {
- bdcopy(u, w, n);
- return 0;
- }
-
- for (i = n; --i >= 0; ) {
- dig = ((uword)u[i] << k) + c;
- w[i] = lo(dig);
- c = hi(dig);
- }
- return c;
- }
-
- /*
- * (u,n) : k
- *
- * k in 0 .. B-1
- */
-
- static word cmpi1(u, k, n)
- DIGIT *u;
- word k;
- word n;
- {
- word i;
-
- for (i = 0; i < n-1; i++)
- if (u[i])
- return 1;
- if (u[n - 1] == (DIGIT)k)
- return 0;
- return u[n - 1] > (DIGIT)k ? 1 : -1;
- }
-
- static novalue bdzero(dest, l)
- DIGIT *dest;
- word l;
- {
- word i;
-
- for (i = 0; i < l; i++)
- dest[i] = 0;
- }
-
- static novalue bdcopy(src, dest, l)
- DIGIT *src, *dest;
- word l;
- {
- word i;
-
- for (i = 0; i < l; i++)
- dest[i] = src[i];
- }
- #else /* LargeInts */
- static char x; /* prevent empty module */
- #endif /* LargeInts */
-